/*
 * Copyright (c) 2017,安徽皖通科技股份有限公司 All rights reserved.
 */

package com.wttech.dzzf.process.service.initilize;

import com.wtkj.vo.dzzf.base.kfwd.FundAccount;
import com.wttech.dzzf.process.dao.RepeatUserInfoDao;
import com.wttech.dzzf.process.dao.TransferUserInfoDao;
import com.wttech.dzzf.process.model.CertKey;
import com.wttech.dzzf.process.model.CertKeyTemp;
import com.wttech.dzzf.process.model.RepeatKey;
import com.wttech.dzzf.process.model.user.User;
import com.wttech.dzzf.process.service.base.BaseInfoService;
import com.wttech.dzzf.process.service.user.UserDetailInfosCreatorService;
import com.wttech.dzzf.process.util.BusinessUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;

import static com.wttech.dzzf.process.constant.UserConstants.DEFAULT_PROCESS_NUM;

/**
 * 数据初始化服务
 *
 * @author MaShibo
 * @date 2017/10/23
 */
@Service
public class DataInitilizingService {

	private static final Logger LOGGER = LoggerFactory.getLogger(DataInitilizingService.class);

	private static final String DEFAULT_TOPCLASS = "6101";

	@Resource
	private TransferUserInfoDao transferUserInfoDao;

	@Resource
	private RepeatUserInfoDao repeatUserInfoDao;

	@Resource
	private FundAccountProcessService fundAccountProcessService;

	@Resource
	private UserDetailInfosCreatorService userDetailInfosCreatorService;

	@Resource
	private BaseInfoService baseInfoService;

	@Resource
	private ThreadPoolTaskExecutor executor;

	private boolean isRunning = false;

	/**
	 * 处理非重复资金账户信息
	 */
	private void processNormalData() {
		LOGGER.info("开始处理非重复数据");
		Integer total = transferUserInfoDao.queryAccountNumV2(true);
		LOGGER.info("共{}条正常数据待处理", total);
		int count = (int) Math.ceil((double) total / DEFAULT_PROCESS_NUM);
		LOGGER.info("共需要处理{}次", count);
		List<Future<Void>> futures = new ArrayList<>(count);
		for (int i = 0; i < count; i++) {
			int num = i + 1;
			futures.add(executor.submit(() -> processNormalUserOnce(num)));
		}
		baseInfoService.getFutureResult(futures);
	}


	/**
	 * 单次处理资金账户信息
	 *
	 * @param num 第num次处理
	 * @return 空
	 */
	private Void processNormalUserOnce(int num) {
		LOGGER.info("第{}次，开始执行...", num);
		int startRow = (num - 1) * DEFAULT_PROCESS_NUM + 1;
		int endRow = num * DEFAULT_PROCESS_NUM;
		List<FundAccount> fundAccounts = transferUserInfoDao.queryNormalAccountInfosV2(startRow, endRow);
		fundAccounts.forEach(this::processOnce);
		LOGGER.info("第{}次，结束执行...", num);
		return null;
	}


	private void processOnce(FundAccount fundAccount) {
		try {
			User user = userDetailInfosCreatorService.buildUserInfo(fundAccount);
			fundAccountProcessService.createUserOrCompanyInfo(fundAccount, user);
			processFundAccount(fundAccount, user);
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
			baseInfoService.createFailtureId(fundAccount.getFundAccountId());
		}
	}

	/**
	 * 单次处理资金账户入口
	 *
	 * @param fundAccount 资金账户
	 * @param user        客户信息
	 */
	private void processFundAccount(FundAccount fundAccount, User user) {
		try {
			fundAccountProcessService.processFundAccount(fundAccount, user);
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
	}


	//~ 处理重复资金账户
	// =========================================================


	/**
	 * 处理重复资金账户信息
	 */
	private void processAbnormalData() {
		List<CertKey> certKeys = repeatUserInfoDao.queryAllRepeatCertInfos();
		int total = certKeys.size();
		LOGGER.info("共{}个重复的证件信息待处理", total);
		List<Future<Void>> futures = new ArrayList<>(total);
		certKeys.forEach(certKey -> futures.add(executor.submit(() -> processRepeatUserOnce(certKey))));
		baseInfoService.getFutureResult(futures);
		LOGGER.info("重复客户信息生成完毕");
	}

	private Void processRepeatUserOnce(CertKey certKey) {
		String certifiNo = certKey.getCertifiNo();
		int certifiType = certKey.getCertifiType();
		LOGGER.info("正在处理重复证件号【{}】， 证件类型【{}】", certifiNo, certifiType);
		List<FundAccount> fundAccounts = repeatUserInfoDao.queryFundAccountByCertInfo(certifiNo, certifiType);
		try {
			if (BusinessUtils.isCompanyCertifiType(certifiType)) {
				//单位用户
				processCompanyInfo(fundAccounts);
			} else if (BusinessUtils.isPersonCertifiType(certifiType)) {
				//个人用户
				processUserInfo(fundAccounts);
			} else {
				LOGGER.error("证件号【{}】，证件类型【{}】无法确定用户类型", certifiNo, certifiType);
			}
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
		return null;
	}


	/**
	 * 处理个人用户 重复数据，合并账户
	 *
	 * @param accounts 重复的资金账户信息
	 */
	private void processUserInfo(List<FundAccount> accounts) {
		FundAccount first = accounts.get(0);
		User user = userDetailInfosCreatorService.buildUserInfo(first);
		fundAccountProcessService.createUserOrCompanyInfo(first, user);
		accounts.forEach(fundAccount -> fundAccountProcessService.processFundAccount(fundAccount, user));
	}

	/**
	 * 处理单位用户重复数据，每个账户创建一条客户信息
	 *
	 * @param accounts 重复的资金账户信息
	 */
	private void processCompanyInfo(List<FundAccount> accounts) {
		Map<String, Integer> departNoMap = new HashMap<>(accounts.size());
		//分组数据
		Map<RepeatKey, List<FundAccount>> groups = new HashMap<>();
		//未分组数据
		List<FundAccount> notGropList = new ArrayList<>();
		accounts.forEach(fundAccount -> {
			RepeatKey pk = new RepeatKey(fundAccount.getAgentIdType(), fundAccount.getAgentIdNum());
			if (pk.canGroup()) {
				if (groups.containsKey(pk)) {
					groups.get(pk).add(fundAccount);
				} else {
					List<FundAccount> group = new ArrayList<>();
					group.add(fundAccount);
					groups.put(pk, group);
				}
			} else {
				notGropList.add(fundAccount);
			}
		});

		//未分组数据遍历处理
		notGropList.forEach(fundAccount -> {
			User user = userDetailInfosCreatorService.buildUserInfo(fundAccount);
			user.setDepartment(buildDepartment(fundAccount, departNoMap));
			fundAccountProcessService.createUserOrCompanyInfo(fundAccount, user);
			processFundAccount(fundAccount, user);
		});

		//分组数据
		groups.forEach((k, v) -> {
			FundAccount first = v.get(0);
			User user = userDetailInfosCreatorService.buildUserInfo(first);
			user.setDepartment(buildDepartment(first, departNoMap));
			fundAccountProcessService.createUserOrCompanyInfo(first, user);
			v.forEach(fundAccount -> processFundAccount(fundAccount, user));
		});

	}

	private String buildDepartment(FundAccount fundAccount, Map<String, Integer> departNoMap) {
		String seqStr = (StringUtils.isBlank(fundAccount.getTopClass()) ? DEFAULT_TOPCLASS : fundAccount.getTopClass()) + fundAccount.getAccountType();
		if (!departNoMap.containsKey(seqStr)) {
			departNoMap.put(seqStr, 1);
		} else {
			int seqNo = departNoMap.get(seqStr);
			departNoMap.put(seqStr, seqNo + 1);
		}
		return seqStr + departNoMap.get(seqStr);
	}

	void recordFailCert(CertKey certKey) {
		try {
			CertKeyTemp temp = new CertKeyTemp();
			temp.setCertifiNo(certKey.getCertifiNo());
			temp.setCertifiType(certKey.getCertifiType());
			transferUserInfoDao.createTestObjcet(temp);
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
	}

	private void shutDownExecutor() {
		isRunning = false;
		executor.shutdown();
	}

	boolean isRunning() {
		return isRunning;
	}

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		DataInitilizingService service = context.getBean(DataInitilizingService.class);
		service.isRunning = true;
		service.processNormalData();
	}
}
